package org.example.MedicalCrowdsourcing.service;

import org.example.MedicalCrowdsourcing.model.entity.BlockchainProject;
import org.example.MedicalCrowdsourcing.model.entity.BlockchainTransaction;
import org.example.MedicalCrowdsourcing.model.entity.User;
import org.example.MedicalCrowdsourcing.repository.BlockchainProjectRepository;
import org.example.MedicalCrowdsourcing.repository.BlockchainTransactionRepository;
import org.example.MedicalCrowdsourcing.repository.UserRepository;
import org.fisco.bcos.sdk.transaction.model.dto.CallResponse;
import org.fisco.bcos.sdk.transaction.model.dto.TransactionResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

/**
 * 区块链数据同步服务
 * 负责将区块链上的数据同步保存到本地数据库
 */
@Service
public class BlockchainSyncService {
    private static final Logger logger = LoggerFactory.getLogger(BlockchainSyncService.class);

    @Autowired
    private BlockchainProjectRepository blockchainProjectRepository;

    @Autowired
    private BlockchainTransactionRepository blockchainTransactionRepository;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    @Qualifier("MedicalCrowdsourcingService")
    private Map<String, MedicalCrowdsourcingService> serviceMap;

    /**
     * 保存项目到本地数据库
     */
    @Transactional
    public BlockchainProject saveProjectToLocal(
            BigInteger blockchainId, 
            String title, 
            String description, 
            Integer status,
            String dataHash,
            String blockchainHash,
            String creatorUsername) {
        
        logger.info("保存/更新区块链项目到本地数据库: ID={}, 标题={}", blockchainId, title);
        
        // 查找是否已存在
        Optional<BlockchainProject> existingProject = blockchainProjectRepository.findByBlockchainId(blockchainId);
        BlockchainProject project;
        
        if (existingProject.isPresent()) {
            // 更新现有项目
            project = existingProject.get();
            project.setTitle(title);
            project.setDescription(description);
            project.setStatus(status);
            project.setDataHash(dataHash);
            project.setBlockchainHash(blockchainHash);
            project.setUpdatedAt(LocalDateTime.now());
            
            if (status == 2) { // 已完成
                project.setCompletedAt(LocalDateTime.now());
            }
            
            logger.info("更新现有区块链项目: ID={}", blockchainId);
        } else {
            // 创建新项目
            project = new BlockchainProject();
            project.setBlockchainId(blockchainId);
            project.setTitle(title);
            project.setDescription(description);
            project.setStatus(status);
            project.setDataHash(dataHash);
            project.setBlockchainHash(blockchainHash);
            
            // 设置创建者
            if (creatorUsername != null) {
                userRepository.findByUsername(creatorUsername).ifPresent(user -> {
                    project.setCreator(user);
                    logger.info("设置项目创建者: {}", creatorUsername);
                });
            }
            
            logger.info("创建新区块链项目: ID={}", blockchainId);
        }
        
        BlockchainProject savedProject = blockchainProjectRepository.save(project);
        logger.info("区块链项目已保存到数据库: ID={}", blockchainId);
        return savedProject;
    }

    /**
     * 保存交易到本地数据库
     */
    @Transactional
    public BlockchainTransaction saveTransactionToLocal(
            BigInteger blockchainId,
            String transactionHash,
            BigInteger blockNumber,
            String status,
            String dataContent,
            BigInteger projectId,
            String creatorUsername) {
        
        logger.info("保存区块链交易到本地数据库: 交易哈希={}, 项目ID={}", transactionHash, projectId);
        
        // 查找是否已存在
        Optional<BlockchainTransaction> existingTransaction = 
                blockchainTransactionRepository.findByTransactionHash(transactionHash);
        
        if (existingTransaction.isPresent()) {
            logger.info("交易已存在，不重复保存: {}", transactionHash);
            return existingTransaction.get(); // 交易已存在，直接返回
        }
        
        // 创建新交易记录
        BlockchainTransaction transaction = new BlockchainTransaction();
        transaction.setBlockchainId(blockchainId);
        transaction.setTransactionHash(transactionHash);
        transaction.setBlockNumber(blockNumber);
        transaction.setStatus(status);
        transaction.setDataContent(dataContent);
        
        // 设置关联的项目
        Optional<BlockchainProject> project = blockchainProjectRepository.findByBlockchainId(projectId);
        if (project.isPresent()) {
            transaction.setProject(project.get());
            logger.info("关联到项目: {}", projectId);
        } else {
            logger.warn("未找到关联项目: {}", projectId);
        }
        
        // 设置创建者
        if (creatorUsername != null) {
            userRepository.findByUsername(creatorUsername).ifPresent(user -> {
                transaction.setCreator(user);
                logger.info("设置交易创建者: {}", creatorUsername);
            });
        }
        
        BlockchainTransaction savedTransaction = blockchainTransactionRepository.save(transaction);
        logger.info("区块链交易已保存到数据库: {}", transactionHash);
        return savedTransaction;
    }

    /**
     * 在区块链操作完成后同步保存交易数据
     */
    @Transactional
    public void syncTransactionAfterBlockchainOperation(
            TransactionResponse response, 
            BigInteger projectId, 
            String dataContent,
            String creatorUsername) {
        
        try {
            String transactionHash = response.getTransactionReceipt().getTransactionHash();
            String status = response.getTransactionReceipt().getStatus();
            String blockNumberStr = response.getTransactionReceipt().getBlockNumber();
            BigInteger blockNumber = new BigInteger(blockNumberStr);
            
            logger.info("开始同步区块链交易数据: 交易哈希={}, 区块号={}", transactionHash, blockNumber);
            
            // 生成事务ID (这里简单处理，实际应用中可能需要更复杂的ID生成策略)
            BigInteger transactionId = new BigInteger(
                    String.valueOf(System.currentTimeMillis()).substring(5));
            
            // 保存交易记录
            saveTransactionToLocal(
                    transactionId,
                    transactionHash,
                    blockNumber,
                    status,
                    dataContent,
                    projectId,
                    creatorUsername
            );
            
            logger.info("交易数据已同步到本地数据库: {}", transactionHash);
        } catch (Exception e) {
            logger.error("同步交易数据到本地失败: {}", e.getMessage(), e);
            throw new RuntimeException("同步交易数据失败", e);
        }
    }
    
    /**
     * 异步同步区块链数据到本地数据库
     */
    public CompletableFuture<Void> asyncSyncBlockchainData(
            TransactionResponse response, 
            BigInteger projectId, 
            String dataContent,
            String creatorUsername) {
        
        return CompletableFuture.runAsync(() -> {
            syncTransactionAfterBlockchainOperation(response, projectId, dataContent, creatorUsername);
        });
    }
    
    /**
     * 获取项目的所有区块链交易
     */
    public List<BlockchainTransaction> getProjectTransactions(BigInteger projectId) {
        Optional<BlockchainProject> project = blockchainProjectRepository.findByBlockchainId(projectId);
        if (project.isPresent()) {
            return blockchainTransactionRepository.findByProject(project.get());
        }
        return Collections.emptyList();
    }
    
    /**
     * 检查区块链数据与本地数据库的同步状态
     * 如果发现不一致，尝试重新同步
     */
    @Transactional
    public void checkAndResyncBlockchainData() {
        // 这里实现具体的检查和重新同步逻辑
        logger.info("检查区块链数据与本地数据库同步状态");
        // TODO: 根据实际需求实现具体逻辑
    }
} 